package jeudelavie.vue;
import ObservableObserveur.Observateur;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import jeudelavie.controleur.Controleur;
import jeudelavie.modele.Cellule;
import jeudelavie.modele.Plateau;
import org.w3c.dom.*;
import org.xml.sax.SAXException;


public class FenetrePrincipale extends JFrame {

    private Controleur  leControleur;   //Le contrôleur
    private Plateau     plateauDuModele;//Le modèle
    private JPanel      panelPrincipal; //Panel qui contient l'espace de la grille et le menu de droite
    private JPanel      espaceGrille;   //Panel qui contiendra les Panel cellules
    private JPanel      menuDroite;     //Panel qui contient les boutons play et pause
    private JButton     boutonPause;    //Bouton qui permet de mettre en pause le thread
    private JButton     boutonReprise;     //Bouton qui permet de relancer le thread
    private CustomPanel tabCases[][];   //Tableau de MyPanel
   
    //Menu
    private JMenuBar    menu;
    private JMenu       menuFichier;
    private JMenuItem   demarrer;         //Démarre le thread et donc les générations
    private JMenuItem   sauvegarder;      //Sauvegarde la configuration courante dans un fichier XML
    private JMenuItem   charger;          //Charge une configuration à partir d'un fichier XML
    private JMenuItem   quitte;           //Quitte le programme
    private JMenu       menuGenerer;
    private JMenuItem   genereAleatoire;  //Génère une grille aléatoire
    private JMenuItem   genereVide;       //Génère une grille vide
    //Fin menu
    //private int taille;                 //Taille x ou y du tableau    
    
    //Constructeurs
    public FenetrePrincipale(){
//        tabCases = new CustomPanel[taille][taille];
    }

    public FenetrePrincipale(Plateau lePlateau) {
        this.pack();
        plateauDuModele = lePlateau;                                //la vue a une référence sur le modèle
        leControleur = new Controleur(this, plateauDuModele){};    
        //taille = plateauDuModele.getTabCellules().length;           //on récupère la taille pour la création du gridlayout
        
        //Menu
        menu = new JMenuBar();
        menuFichier = new JMenu("Fichier");
        
        //Cette action permet de démarrer le thread
        demarrer = new JMenuItem("Démarrer");
        
        //On ajoute un écouteur au menu demarrer
        demarrer.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                leControleur.lancement();
            }
        });
        menuFichier.add(demarrer);

        sauvegarder = new JMenuItem("Sauvegarder");
        sauvegarder.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                leControleur.saveXml();
            }
        });
        menuFichier.add(sauvegarder);

        charger = new JMenuItem("Charger");
        charger.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                leControleur.loadXml();
            }
        });
        menuFichier.add(charger);

        quitte = new JMenuItem("Quitter");
        quitte.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                leControleur.quitter();
            }
        });
        menuFichier.add(quitte);
        
        menuGenerer = new JMenu("Générer");
        genereAleatoire = new JMenuItem("Aleatoire");
        genereAleatoire.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                leControleur.pause();
                leControleur.genereAleatoire();
            }
        });
        menuGenerer.add(genereAleatoire);

        genereVide = new JMenuItem("Vide");
        genereVide.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                leControleur.pause();
                leControleur.remiseAZero();
            }
        });
        menuGenerer.add(genereVide);
        
        menu.add(menuFichier);
        menu.add(menuGenerer);
        this.setJMenuBar(menu);
        //Fin Menu

        //Panel principal
        panelPrincipal = new JPanel(new BorderLayout());
        //panelPrincipal.setLayout(new BorderLayout());

        this.add(panelPrincipal);
        //Fin Panel principal

        //Panel menu droite
        //Initialisation de l'espace du menu de droite
        menuDroite = new JPanel();
        menuDroite.setPreferredSize(new Dimension(150, 10));
        menuDroite.setSize(150, 10);
        menuDroite.setBackground(Color.DARK_GRAY);
        menuDroite.setBorder(new BevelBorder(0));
        
        //Initialisation du bouton pause du menu de droite
        boutonPause = new JButton("Pause");
        boutonPause.setSize(140, 30);
        boutonPause.setPreferredSize(new Dimension(140, 30));
        boutonPause.setEnabled(false);
        boutonPause.setBorder(new BevelBorder(0));
        boutonPause.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                leControleur.pause();
            }
        });
        
        //Initialisation du bouton lancer du menu de droite
        boutonReprise = new JButton("Lancer");
        boutonReprise.setSize(140, 30);
        boutonReprise.setPreferredSize(new Dimension(140, 30));
        boutonReprise.setBorder(new BevelBorder(0));
        boutonReprise.setEnabled(false);
        boutonReprise.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                leControleur.reprise();
            }
        });

        menuDroite.add(boutonPause);
        menuDroite.add(boutonReprise);
        //Fin menu droite
        
        //Panel espace grille
        //Les cases seront classées à l'aide d'un GridBagLayout
        espaceGrille = new JPanel(new GridBagLayout());
        espaceGrille.setBorder(new BevelBorder(0));
        GridBagConstraints contraintes = new GridBagConstraints();

        //Initialisation du tableau de MyPanel
        tabCases = new CustomPanel[lePlateau.getHauteur()][lePlateau.getLargeur()];
        for(int i = 0; i < lePlateau.getHauteur(); i++)
        {
            for(int j = 0; j < lePlateau.getLargeur(); j++)
            {
                //Initialisation de la cellule MyPanel
                tabCases[i][j] = new CustomPanel(this,i,j);
                tabCases[i][j].setPreferredSize(new Dimension(4, 4));
                tabCases[i][j].setSize(4, 4);
                tabCases[i][j].setBackground(Color.GRAY);
                //La case sera placée à la position (i, j)
                contraintes.gridx = j;
                contraintes.gridy = i;
                espaceGrille.add(tabCases[i][j], contraintes);

                //On ajoute un observeur sur la cellule
                this.plateauDuModele.getCellule(i,j).ajouterObservateur(new Observateur()
                {
                    @Override
                    public void actualiser(Object _cell)
                    {
                        Cellule c = (Cellule)_cell;
                        if( c.getEtatPrecedent()==1)
                        {
                            tabCases[c.getY()][c.getX()].setBackground(Color.GREEN);
                        }
                        else
                        {
                            tabCases[c.getY()][c.getX()].setBackground(Color.GRAY);
                        }
                    }
                });
            }
        }
        panelPrincipal.add(espaceGrille, BorderLayout.CENTER);
        panelPrincipal.add(menuDroite, BorderLayout.EAST);
        
        this.setTitle("Jeu de la vie");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        pack();   
    }
    
    
    //Lorsque l'utilisateur clique sur une case, cette procédure est appelée pour modifier l'état de la cellule
    public void evenementClic(int x, int y){
        leControleur.changeEtatCellule(x, y);
    }    
    
    //Affiche le bouton pause
    public void affichePause(){
        this.boutonPause.setEnabled(true);
    }
    
    //Cache le bouton pause
    public void cachePause(){
        this.boutonPause.setEnabled(false);
    }
    
    //Affiche le bouton reprise
    public void afficheReprise(){
        this.boutonReprise.setEnabled(true);
    }
    
    //Cache le bouton reprise
    public void cacheReprise(){
        this.boutonReprise.setEnabled(false);
    }

    //Permet la sauvegarde
    public void saveXml() {    
        try
        {
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

            Document doc = docBuilder.newDocument();
            Element racine = doc.createElement("grille");
            doc.appendChild(racine);
            for(int i = 0; i < plateauDuModele.getTabCellules().length; ++i)
            {
                for(int j = 0; j < plateauDuModele.getTabCellules().length; ++j)
                {
                    Element e = doc.createElement("Cellule");
                    racine.appendChild(e);

                    Attr atI = doc.createAttribute("i");
                    atI.setValue(Integer.toString(i));
                    e.setAttributeNode(atI);

                    Attr atJ = doc.createAttribute("j");
                    atJ.setValue(Integer.toString(j));
                    e.setAttributeNode(atJ);

                    Element etatIJ = doc.createElement("etat");
                    etatIJ.appendChild(doc.createTextNode(Integer.toString(plateauDuModele.getCellule(j, i).getEtatPrecedent())));
                    e.appendChild(etatIJ);
                }
            }

            //Ecrire le contenu dans le fichier xml
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource source = new DOMSource(doc);
            JFileChooser fc = new JFileChooser();
            fc.setCurrentDirectory(new java.io.File("."));
            fc.setDialogTitle("Sauvegarder");
            fc.setAcceptAllFileFilterUsed(false);
            fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
            if(fc.showSaveDialog(FenetrePrincipale.this) == JFileChooser.APPROVE_OPTION)
            {
                File file = fc.getSelectedFile();
                StreamResult result;
                if(file.getName().toLowerCase().endsWith(".xml"))
                    result = new StreamResult(file.getPath());
                else
                    result = new StreamResult(file.getPath()+".xml");
                transformer.transform(source, result);
            }

        }
        catch(ParserConfigurationException | TransformerException pce)
        {
        }
    }

    //Permet le chargement
    public void loadXml(){
        try
        {
            File fXmlFile;
            JFileChooser fc = new JFileChooser();
            fc.setCurrentDirectory(new java.io.File("."));
            fc.setDialogTitle("Charger fichier XML");
            fc.setAcceptAllFileFilterUsed(false);
            fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
            if(fc.showOpenDialog(FenetrePrincipale.this) == JFileChooser.APPROVE_OPTION)
            {
                fXmlFile = fc.getSelectedFile();
                //S'il s'agit bien d'un fichier XML
                if(fXmlFile.getName().toLowerCase().endsWith(".xml"))
                {
                    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
                    DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
                    Document doc = dBuilder.parse(fXmlFile);
                    doc.getDocumentElement().normalize();

                    System.out.println("Element racine : " + doc.getDocumentElement().getNodeName());
                    NodeList nList = doc.getElementsByTagName("Cellule");

                    for (int temp = 0; temp < nList.getLength(); ++temp)
                    {
                        Node nNode = nList.item(temp);
                        if (nNode.getNodeType() == Node.ELEMENT_NODE)
                        {
                            Element eElement = (Element) nNode;
                            leControleur.modifierCellule(Integer.parseInt(eElement.getAttribute("j")),
                                    Integer.parseInt(eElement.getAttribute("i")),
                                    Integer.parseInt(getTagValue("etat",eElement)));
                            
                        }
                    }
                    for (int i = 0 ; i<tabCases.length ; i++){
                        for (int j = 0 ; j<tabCases.length ; j++){
                            plateauDuModele.getCellule(i, j).notifierObservateur();
                        }
                    }
                }
                else
                {
                    System.out.println("Erreur de fichier (extension .xml attendue !).");
                }
            }
        }
        catch (HeadlessException | ParserConfigurationException | SAXException | IOException | NumberFormatException e)
        {
        }
    }
    
    //Permet de tagger les noeuds XML
    private static String getTagValue(String sTag, Element eElement){
        NodeList nlList= eElement.getElementsByTagName(sTag).item(0).getChildNodes();
        Node nValue = (Node) nlList.item(0);

        return nValue.getNodeValue();
    }
}
